﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Content;
using RabbitMQ.Client.Events;

namespace AutoAllocService.Messaging
{
    public class RabbitMqHelper : IDisposable
    {
        private static RabbitMqHelper _instance;

        public static RabbitMqHelper Instance => _instance ?? (_instance = new RabbitMqHelper());

        public static string QUEUE_RESULT_NAME = Program.AppSetting.Rabbit.QueuePrefix + "auto_alloc.result";
        public static string QUEUE_REQ_NAME = Program.AppSetting.Rabbit.QueuePrefix + "auto_alloc.request";

        private readonly object _lock = new object();

        private readonly IConnectionFactory _connectionFactory;
        private readonly IConnection _connection;
        private readonly IModel _channel;

        private bool _stop = false;

        public RabbitMqHelper()
        {
            _connectionFactory = new ConnectionFactory
            {
                HostName = Program.AppSetting.Rabbit.Host,
                Port = Program.AppSetting.Rabbit.Port,
                UserName = Program.AppSetting.Rabbit.User,
                Password = Program.AppSetting.Rabbit.Password
            };
            _connection = _connectionFactory.CreateConnection();
            _channel = _connection.CreateModel();
            _channel.QueueDeclare(QUEUE_RESULT_NAME, autoDelete: false, exclusive: false);
        }

        public void Consume(string queue_name, Action<string> handleMsgAction)
        {
            using (var connection = _connectionFactory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.QueueDeclare(QUEUE_REQ_NAME, autoDelete: false, exclusive: false);

                    //var consumer = new QueueingBasicConsumer(channel);
                    var consumer = new EventingBasicConsumer(channel);

                    consumer.Received += (s, ea) =>
                    {
                        byte[] bytes = ea.Body;
                        string str = Encoding.UTF8.GetString(bytes);
                        //Console.WriteLine("HandleMsg:" + str);

                        if (handleMsgAction != null)
                        {
                            try
                            {
                                handleMsgAction.Invoke(str);
                                //回复确认
                                channel.BasicAck(ea.DeliveryTag, false);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e);
                            }
                        }
                    };

                    channel.BasicConsume(QUEUE_REQ_NAME, false, consumer);

                    while (!_stop)
                    {
                        //BasicDeliverEventArgs ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                        //byte[] bytes = ea.Body;
                        //string str = Encoding.UTF8.GetString(bytes);
                        ////Console.WriteLine("HandleMsg:" + str);

                        //if (handleMsgAction != null)
                        //{
                        //    try
                        //    {
                        //        handleMsgAction.Invoke(str);
                        //        //回复确认
                        //        channel.BasicAck(ea.DeliveryTag, false);
                        //    }
                        //    catch (Exception e)
                        //    {
                        //        Console.WriteLine(e);
                        //    }
                        //}
                        System.Threading.Thread.Sleep(200);
                    }
                }
            }
        }

        public void EnqueueResult<T>(T msg)
        {
            lock (_lock)
            {
                var json = JsonConvert.SerializeObject(msg);

                var basic = _channel.CreateBasicProperties();
                //channel.BasicPublish(model.Exchange, model.Topic, (IBasicProperties)b.GetContentHeader(), b.GetContentBody());

                _channel.BasicPublish("", QUEUE_RESULT_NAME, basic, Encoding.UTF8.GetBytes(json));

            }
        }

        public void Stop()
        {
            _stop = true;
        }

        public void Dispose()
        {
            _connection?.Dispose();
            _channel?.Dispose();
        }
    }
}
